﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace PortScan
{
    class Program
    {
        static void Waiting(CancellationToken ct)
        {
            while (! ct.IsCancellationRequested)
            {
                Console.Write(".");
                Thread.Sleep(1000);
            }
            //Console.WriteLine("Cancellation requested");
        }

        static void Main(string[] args)
        {
            string name = (args.Length < 1) ? Dns.GetHostName() : args[0];
            Server srv = new Server("localhost");

            //handle the waiting task and enable cancellation of the task so we can end it when all the treads have completed
            Console.Write("Waiting ...");
            var waitTokenSource = new CancellationTokenSource();
            var waitToken = waitTokenSource.Token;
            Task.Factory.StartNew(() =>  Waiting(waitToken), waitToken);
     
            //delegate function to safely encapsulate thread information
            Func<object, PortInfo> runthreads = (object obj) =>
            {
                int i = (int)obj;
                return PortCheck.Check(srv.ipv4addrs[0], i);
            };

            //create the array and start the tasks
            Task<PortInfo>[] taskArray = new Task<PortInfo>[100];
            for (int i = 0; i < taskArray.Length; i++)
            {
                taskArray[i] = Task<PortInfo>.Factory.StartNew(runthreads, i);
            }

            //wait on all the tasks to complete
            try
            {
                Task.WaitAll(taskArray); //wait that all the threads running portcheck are finished         
            }
            catch (AggregateException e)
            {
                for (int j = 0; j < e.InnerExceptions.Count; j++)
                {
                    Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
                }
            }

            //cancel the waiting task
            waitTokenSource.Cancel();

            //var tasks = from t in taskArray orderby t.Result.number select t; //not necessary as tasks arlready ordered correctly
           
            //process the results
            foreach (Task<PortInfo> task in taskArray)
            {
                if (task.Result.open)   { Console.WriteLine(task.Result.ipaddr + " : " + task.Result.number + " is open "); }
                else                    { Console.WriteLine(task.Result.ipaddr + " : " + task.Result.number + " is closed "); };
            }

            Console.WriteLine("\nFinished"); //once done

            //Wait before close console
            Console.ReadLine();
        }
    }
}
